#include "stdafx.h"
#include "BridgeComponentBase.h"

#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Shell.hxx>


#include <GC_MakeSegment.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <GeomPlate_BuildPlateSurface.hxx>
#include <BRepFill_CurveConstraint.hxx>
#include <GeomPlate_MakeApprox.hxx>
#include <GeomPlate_Surface.hxx>
#include <Geom_BSplineSurface.hxx>
#include <BRepBuilderAPI_Transform.hxx>
DEFINE_CREATE_CLASS(BridgeComponentBase, "BridgeComponentBase")
BridgeComponentBase::BridgeComponentBase(ZMString materialName) :
	m_materialName(materialName)
{
	InitParam();
}


BridgeComponentBase::~BridgeComponentBase()
{
}

int BridgeComponentBase::SetParamValue(const ZMString& strName, const ZMString& strValue)
{
	int iRet = 0;
	if (m_vParamInfo.find(strName) == m_vParamInfo.end())
	{
		iRet = 1;
	}
	else
	{
		suParamInfo&info = m_vParamInfo[strName];
		info.m_strValue = strValue;
	}

	for (SharedPointer<UIDataBase> pParam : m_vParam)
	{
		if (pParam->GetAttachFuncName().isEmpty())
		{
			QString id = pParam->GetID();
			if (ToString(id) == strName)
			{
				pParam->SetData(ToQString(strValue));
			}
		}
	}

	return iRet;
}

ZMVector<BridgeComponentBase::suParamInfo> BridgeComponentBase::GetParamInfo() const
{
	ZMVector<BridgeComponentBase::suParamInfo> ret;
	for (map<ZMString, suParamInfo>::const_iterator pos = m_vParamInfo.begin(); pos != m_vParamInfo.end(); ++pos)
	{
		ret.push_back(pos->second);
	}
	return ret;
}

TopoDS_Shape BridgeComponentBase::CreateShapeMain()
{
	TopoDS_Shape ret = CreateShape();
	gp_Trsf t;
	t.SetScaleFactor(0.01);
	BRepBuilderAPI_Transform tran(t);
	tran.Perform(ret);
	assert(tran.IsDone());

	return tran.Shape();
}

TopoDS_Shape BridgeComponentBase::CreateShape()
{
	assert(false);
	return TopoDS_Shape();
}

void BridgeComponentBase::AddParam(const ZMString& strName, const emParamType& paramType, const ZMString& strValue)
{
	suParamInfo info;
	info.m_paramType = paramType;
	info.m_strName = strName;
	info.m_strValue = strValue;
	m_vParamInfo[strName] = info;
}

ZMVector<MeshObjectBase::suDrawMesh> BridgeComponentBase::GetMeshData(const ZMString& strMeshName)
{
	ZMVector<suDrawMesh> ret;
	TopoDS_Shape shape = CreateShapeMain();
	ZMString strNodeName = strMeshName == "" ? GetObjName() : strMeshName;

	suDrawMesh drawMesh;
	drawMesh.m_pMeshData = SharedPointer<MeshData>(new MeshData);
	MeshData&meshData = *drawMesh.m_pMeshData;

	ZMVector<ZMPoint3D> vPntData;
	ZMVector<ZMPoint3D> vNormalData;
	ZMVector<ZMPoint3D> vTangentData;
	ZMVector<ZMPoint2D> vUVData;
	ZMVector<int> vTriIndex;

	TriangleShapeWithOcc(shape, vPntData, vUVData, vNormalData, vTangentData, vTriIndex);

	meshData.SetMeshName(strNodeName);
	meshData.SetPntData(vPntData);
	meshData.SetNormalData(vNormalData);
	meshData.SetTriIndex(vTriIndex);
	meshData.SetTangentData(vTangentData);
	meshData.SetUVData(vUVData);

	drawMesh.m_strMatName = m_materialName;
	drawMesh.m_strNodeName = strNodeName;

	ret.push_back(drawMesh);
	return ret;
}

ZMVector<TopoDS_Edge> BridgeComponentBase::CreateEdgeFromPnt(const ZMVector<ZMPoint3D>& vPntOrign)
{
	ZMVector<TopoDS_Edge> vEdge;
	ZMVector<ZMPoint3D> vPnt = vPntOrign;
	if (vPnt[vPnt.size() - 1].Distance(vPnt[0]) > 0.001)
	{
		vPnt.push_back(vPnt[0]);
	}
	for (int i = 0; i < vPnt.size() - 1; ++i)
	{
		gp_Pnt pntFrom(vPnt[i][0], vPnt[i][1], vPnt[i][2]), pntTo(vPnt[i + 1][0], vPnt[i + 1][1], vPnt[i + 1][2]);
		Handle(Geom_TrimmedCurve) aSegment1 = GC_MakeSegment(pntFrom, pntTo);
		vEdge.push_back(BRepBuilderAPI_MakeEdge(aSegment1).Edge());
	}
	return vEdge;
}
TopoDS_Wire BridgeComponentBase::CreateWireFromPnts(const ZMVector<ZMPoint3D>& vPntOrign)
{
	ZMVector<TopoDS_Edge> vEdge = CreateEdgeFromPnt(vPntOrign);
	BRepBuilderAPI_MakeWire mkWire;
	for (const TopoDS_Edge& edge : vEdge)
	{
		mkWire.Add(edge);
	}
	TopoDS_Wire wire = mkWire.Wire();
	return wire;
}

TopoDS_Shape BridgeComponentBase::CreatePrismFromPnts(const ZMVector<ZMPoint3D>& vPntOrign, const ZMPoint3D& dir, ZMReal dDis)
{
	TopoDS_Shape ret;
	try
	{
		
		TopoDS_Wire wire = CreateWireFromPnts(vPntOrign);

		BRepBuilderAPI_MakeFace mkFace = BRepBuilderAPI_MakeFace(wire);
		TopoDS_Face face;

		if (mkFace.IsDone())
		{
			face = mkFace.Face();
		}
		else
		{
			ZMVector<TopoDS_Edge> vEdge = CreateEdgeFromPnt(vPntOrign);

			GeomPlate_BuildPlateSurface bpSrf(3, 9, 12,0.01, 0.01);
			for (const TopoDS_Edge& edge : vEdge)
			{
				Handle(BRepAdaptor_HCurve) c(new BRepAdaptor_HCurve());
				c->ChangeCurve().Initialize(edge);
				Handle(BRepFill_CurveConstraint) constraint(new BRepFill_CurveConstraint(c,0, 10,0.01 ));
				bpSrf.Add(constraint);
			}
			bpSrf.Perform();
			Handle(GeomPlate_Surface) hSurface = bpSrf.Surface();
			Standard_Real U1, U2, V1, V2;

			GeomPlate_MakeApprox plate(hSurface, 0.01, 10, 5, 0.01, 0, GeomAbs_C0);
			hSurface->Bounds(U1, U2, V1, V2);

			BRepBuilderAPI_MakeFace mkFace1(plate.Surface(), U1, U2, V1, V2, 1e-6);
			assert(mkFace1.IsDone());
			face = mkFace1.Face();
		}
		gp_Vec d = gp_Vec(dir[0] * dDis, dir[1] * dDis, dir[2] * dDis);


		ret = BRepPrimAPI_MakePrism(face, d).Shape();
	}
	catch (const Standard_Failure& err)
	{
		QString str;
		str = QString( "\nStandard_Failure:" )+ QString(err.GetMessageString());
		str = str;
	}
	catch (...)
	{
		QString str;
		str = QString("\nBRepPrimAPI_MakePrism some unknown errors occur");
		str = str;
	}
	return ret;
}

void BridgeComponentBase::SetParamCore(const ZMVector<SharedPointer<UIDataBase>>& vParam)
{
	m_vParam = vParam;
	for (SharedPointer<UIDataBase> pParam : vParam)
	{
		if (pParam->GetAttachFuncName().isEmpty())
		{
			QString id = pParam->GetID();
			if (m_vParamInfo.find(ToString(id)) != m_vParamInfo.end())
			{
				m_vParamInfo[ToString(id)].m_strValue = ToString(pParam->GetValue().toString());
			}
		}
	}
}

void BridgeComponentBase::WritePnt(const QString& strName, const ZMVector<ZMPoint3D>& vPnt)
{
	CFileSaveData fp(strName);
	fp << "3dpoly ";
	for (ZMVector<ZMPoint3D>::const_iterator pos = vPnt.begin(); pos != vPnt.end(); ++pos)
	{
		ZMPoint3D pnt = *pos;
		fp << pnt.x() << ",";		fp << pnt.y() << ",";		fp << pnt.z() << "\r\n";
	}
	fp << "\r\n";
}
